package org.opu.gui.docviewer.table;

import java.util.ArrayList;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.SimpleAttributeSet;

/**
 *  Modern DefaultStyledDocument require structured representation
 * of text (tables). The tables consist of rows and columns and
 * framed by a colored border (black in the article) and may contain
 * paragraphs of text and images as well as nested tables. The
 * cells (and rows) automatically increase their height according t
 * o height of content.
 * <br>
 * Basically the hierarchy is organized in 3 levels.
 * <pre>
 * Root
 *   Paragraph
 *      Text.
 * </pre>
 * <br>
 * To add JEditorPane's tables we should change the structure to be like this:
 * <pre>
 * Root
 *   Paragraph
 *      Text
 *   Table
 *       Row(s)
 *         Cell(s)
 *           Paragraph(s)
 *             Text
 * </pre>
 *
 * @author yura
 */
public class TableDocument extends DefaultStyledDocument {

    /** Element name table */
    public static final String ELEMENT_NAME_TABLE = "table";

    /** Element name row */
    public static final String ELEMENT_NAME_ROW = "row";

    /** Element name cell */
    public static final String ELEMENT_NAME_CELL = "cell";

    /** Parmeter of cell - cell width */
    public static final String PARAM_CELL_WIDTH = "cell-width";

    /**
     * Constructs a talbe document. This buffers input content
     * by a size of BUFFER_SIZE_DEFAULT and has a style context
     * that is scoped by the lifetime of the document and is not
     * shared with other documents.
     */
    public TableDocument() {
    }

    /**
     *  Pass offset in the document where the table will be inserted,
     * row count and width of the table’s columns. Size of the array
     * defines column count in the table.
     * 
     * @param offset the starting offset >= 0
     * @param rowCount number of row in table
     * @param colWidths array of cell width
     * @throws BadLocationException for an invalid starting offset
     */
    public void insertTable(int offset, int rowCount, int[] colWidths) throws BadLocationException {
        //try {
        SimpleAttributeSet attrs = new SimpleAttributeSet();

        ArrayList tableSpecs = new ArrayList();
        tableSpecs.add(new ElementSpec(attrs, ElementSpec.EndTagType)); //close paragraph tag

        SimpleAttributeSet tableAttrs = new SimpleAttributeSet();
        tableAttrs.addAttribute(ElementNameAttribute, ELEMENT_NAME_TABLE);
        ElementSpec tableStart = new ElementSpec(tableAttrs, ElementSpec.StartTagType);
        tableSpecs.add(tableStart); //start table tag

        fillRowSpecs(tableSpecs, rowCount, colWidths);

        ElementSpec tableEnd = new ElementSpec(tableAttrs, ElementSpec.EndTagType);
        tableSpecs.add(tableEnd); //end table tag

        tableSpecs.add(new ElementSpec(attrs, ElementSpec.StartTagType)); //open new paragraph after table

        ElementSpec[] spec = new ElementSpec[tableSpecs.size()];
        tableSpecs.toArray(spec);

        this.insert(offset, spec);
        //} catch (BadLocationException ex) {
        //    ex.printStackTrace();
        //}
    }

    /**
     *  Appending rows to tableSpecs list
     *
     * @param tableSpecs list where rows will be added
     * @param rowCount number of additing rows
     * @param colWidths  array of cell width
     */
    protected void fillRowSpecs(ArrayList tableSpecs, int rowCount, int[] colWidths) {
        SimpleAttributeSet rowAttrs = new SimpleAttributeSet();
        rowAttrs.addAttribute(ElementNameAttribute, ELEMENT_NAME_ROW);

        for (int i = 0; i < rowCount; i++) {
            ElementSpec rowStart = new ElementSpec(rowAttrs, ElementSpec.StartTagType);
            tableSpecs.add(rowStart);

            fillCellSpecs(tableSpecs, colWidths);

            ElementSpec rowEnd = new ElementSpec(rowAttrs, ElementSpec.EndTagType);
            tableSpecs.add(rowEnd);
        }

    }

    /**
     *  Appending cells to tableSpecs list
     *
     * @param tableSpecs list where cells will be added
     * @param colWidths array of cell width
     */
    protected void fillCellSpecs(ArrayList tableSpecs, int[] colWidths) {
        for (int i = 0; i < colWidths.length; i++) {
            fellCell(tableSpecs, colWidths[i]);
        }
    }

    /**
     *  Appending won cell to tableSpecs list
     *
     * @param tableSpecs list where cells will be added
     * @param colWidths cell width
     */
    protected void fellCell(ArrayList tableSpecs, int colWidths) {
        SimpleAttributeSet cellAttrs = new SimpleAttributeSet();
        cellAttrs.addAttribute(ElementNameAttribute, ELEMENT_NAME_CELL);
        cellAttrs.addAttribute(PARAM_CELL_WIDTH, new Integer(colWidths));
        ElementSpec cellStart = new ElementSpec(cellAttrs, ElementSpec.StartTagType);
        tableSpecs.add(cellStart);
        ElementSpec parStart = new ElementSpec(new SimpleAttributeSet(), ElementSpec.StartTagType);
        tableSpecs.add(parStart);
        ElementSpec parContent = new ElementSpec(new SimpleAttributeSet(),
                ElementSpec.ContentType, "\n".toCharArray(), 0, 1);
        tableSpecs.add(parContent);
        ElementSpec parEnd = new ElementSpec(new SimpleAttributeSet(), ElementSpec.EndTagType);
        tableSpecs.add(parEnd);
        ElementSpec cellEnd = new ElementSpec(cellAttrs, ElementSpec.EndTagType);
        tableSpecs.add(cellEnd);
    }

    @Override
    public void insert(int offset, ElementSpec[] data) throws BadLocationException {
        super.insert(offset, data);
    }
}
